using System;
using System.Collections.Generic;
using System.Text;
using Lizk.SimpleHUD;
using Lizk.DShowPlayer;
using System.Diagnostics;
using System.Threading;
using XNAHUDEngine;
using System.IO;

namespace SharpMedia.MDX
{
    public class XNAVideoDVD : XNAVideo
    {
        private DVDPlayer player;
        private object loadLock = new object();
        public XNAVideoDVD(XNAForm form, HUDVideo2 video)
            : base(form, video) 
        {
            player = new DVDPlayer(video.SourceUrl);
        }

        public override Player Player
        {
            get { return player; }
        }

        public override void Restart()
        {
            if (player == null)
            {
                player = new DVDPlayer(video.SourceUrl);
                video.Load();
            }
        }

        public override void Unload()
        {
            lock (loadLock)
            {
                if (Disposed)
                    return;

                if (allocator != null)
                    allocator.Close();
                allocator = null;

                if (player != null)
                {
                    if (!video.Closed && (player.State == Lizk.DShowPlayer.PlayerState.Paused || player.State == Lizk.DShowPlayer.PlayerState.Playing || player.State == PlayerState.Menu))
                    {
                        resumeAfterRestart = player.State == Lizk.DShowPlayer.PlayerState.Paused || player.State == Lizk.DShowPlayer.PlayerState.Playing || player.State == PlayerState.Menu;
                        restart = true;
                    }

                    player.Dispose();
                }
                player = null;
                

                if (video.Closed)
                    Disposed = true;
            }
        }

        public override void HandleVideoCommand(HUDVideo2.VideoCommands command, object[] parameters)
        {
            lock (loadLock)
            {
                if(allocator != null)
                    allocator.Wait = true;
                switch (command)
                {
                    case HUDVideo2.VideoCommands.Load:
                        if (player == null || player.State == PlayerState.Disposed)
                            return;
                        allocator = new Allocator2(form.GraphicsDevice, this);
                        
                        player.StateChanged += new EventHandler<Lizk.DShowPlayer.PlayerEventArgs>(player_StateChanged);
                        player.LanguageChanged += new EventHandler<LanguageEventArgs>(player_LanguageChanged);
                        
                        player.TrackAmountChanged += new EventHandler(player_TrackAmountChanged);
                        player.TrackChanged += new EventHandler(player_TrackChanged);
                        player.AfterSendAsync += new EventHandler(player_AfterSendAsync);
                        player.BeforeSendAsync += new EventHandler(player_BeforeSendAsync);
                        player.DiskEjected += new EventHandler(player_DiskEjected);
                        player.DiskError += new EventHandler(player_DiskError);

                        player.Load(form, allocator);
                        player.LoadBookmark(new DriveInfo(video.SourceUrl).VolumeLabel);
                        if (restart)
                        {
                            restart = false;
                        }
                        video.Updater.SetDuration(player.Duration);
                        break;
                    case HUDVideo2.VideoCommands.MenuUp:
                        player.MenuMove(DirectShowLib.Dvd.DvdRelativeButton.Upper);
                        break;
                    case HUDVideo2.VideoCommands.MenuDown:
                        player.MenuMove(DirectShowLib.Dvd.DvdRelativeButton.Lower);
                        break;
                    case HUDVideo2.VideoCommands.MenuLeft:
                        player.MenuMove(DirectShowLib.Dvd.DvdRelativeButton.Left);
                        break;
                    case HUDVideo2.VideoCommands.MenuRight:
                        player.MenuMove(DirectShowLib.Dvd.DvdRelativeButton.Right);
                        break;
                    case HUDVideo2.VideoCommands.MenuSelect:
                        player.MenuSelect();
                        break;
                    case HUDVideo2.VideoCommands.Stop:
                        try
                        {
                            player.SaveBookmark(new DriveInfo(video.SourceUrl).VolumeLabel);
                        }
                        catch { }
                        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { Unload(); }));
                        break;
                    case HUDVideo2.VideoCommands.RootMenu:
                    case HUDVideo2.VideoCommands.TitleMenu:
                        player.RootMenu();
                        break;
                    case HUDVideo2.VideoCommands.SetChapter:
                        int newChapter = (int)parameters[0];
                        if (newChapter == player.CurrentChapter + 1)
                            player.NextChapter();
                        else if (newChapter == player.CurrentChapter - 1)
                            player.PreviousChapter();
                        else if (newChapter >= 0 && newChapter < player.Chapters)
                            player.SetChapter(newChapter);
                        break;
                    case HUDVideo2.VideoCommands.Seek:
                        player.Seek(((TimeSpan)parameters[0]).Ticks, (bool)parameters[1]);
                        break;
                    case HUDVideo2.VideoCommands.Pause:
                        player.Pause();
                        break;
                    case HUDVideo2.VideoCommands.Play:
                        if (player.State == Lizk.DShowPlayer.PlayerState.Paused)
                        {
                            player.Play();
                        }
                        break;
                    case HUDVideo2.VideoCommands.ChangeSubtitle:
                        player.Subtitle = (int)parameters[0];
                        break;
                    case HUDVideo2.VideoCommands.ChangeAudioTrack:
                        player.AudioTrack = (int)parameters[0];
                        break;

                }
                if (allocator != null)
                    allocator.Wait = false;

            }
        }

        void player_DiskError(object sender, EventArgs e)
        {
            video.Close();
        }

        void player_DiskEjected(object sender, EventArgs e)
        {
            video.Close();
        }

        void player_BeforeSendAsync(object sender, EventArgs e)
        {
            if (allocator != null)
                allocator.Wait = true;
        }

        void player_AfterSendAsync(object sender, EventArgs e)
        {
            if (allocator != null)
                allocator.Wait = false;
        }


        void player_StateChanged(object sender, PlayerEventArgs e)
        {

            switch (e.NewState)
            {
                case PlayerState.NotLoaded:
                    video.Updater.SetState(HUDVideo2.PlayerState.NotLoaded);
                    break;
                case PlayerState.Loaded:
                    video.Updater.SetState(HUDVideo2.PlayerState.Stopped);
                    break;
                case PlayerState.Playing:
                    video.Updater.SetState(HUDVideo2.PlayerState.Playing);
                    break;
                case PlayerState.Paused:
                    video.Updater.SetState(HUDVideo2.PlayerState.Paused);
                    break;
                case PlayerState.Disposed:
                    video.Updater.SetState(HUDVideo2.PlayerState.NotLoaded);
                    break;
                case PlayerState.Menu:
                    video.Updater.SetState(HUDVideo2.PlayerState.Menu);
                    break;


            }

            if (e.NewState != PlayerState.Disposed)
            {
                video.Updater.SetDuration(player.Duration);
                video.Updater.SetPosition(player.Position);
            }
        }

        public override void Update()
        {
            if (player != null && player.State != Lizk.DShowPlayer.PlayerState.NotLoaded && player.State != Lizk.DShowPlayer.PlayerState.Disposed)
            {
                video.Updater.SetPosition(player.Position);
                video.Updater.SetDuration(player.Duration);
            }
            base.Update();
        }

        void player_TrackChanged(object sender, EventArgs e)
        {
            video.Updater.SetActiveAngle(player.CurrentAngle);
            video.Updater.SetActiveAudiotrack(player.AudioTrack);
            video.Updater.SetActiveSubtitle(player.Subtitle);
            video.Updater.SetCurrentChapter(player.CurrentChapter);
            video.Updater.SetCurrentTitle(player.CurrentTitle);
        }

        void player_TrackAmountChanged(object sender, EventArgs e)
        {
            List<Lizk.SimpleHUD.HUDVideo2.TrackIdentifier> tracks = new List<HUDVideo2.TrackIdentifier>();
            foreach (KeyValuePair<int, string> kvp in player.Subtitles)
            {
                Lizk.SimpleHUD.HUDVideo2.TrackIdentifier ti = new HUDVideo2.TrackIdentifier();
                ti.id = kvp.Key;
                ti.name = kvp.Value;
                tracks.Add(ti);
            }
            video.Updater.SetSubtitles(tracks);
            tracks.Clear();
            video.Updater.SetActiveSubtitle(player.Subtitle);

            foreach (KeyValuePair<int, string> kvp in player.AudioTracks)
            {
                Lizk.SimpleHUD.HUDVideo2.TrackIdentifier ti = new HUDVideo2.TrackIdentifier();
                ti.id = kvp.Key;
                ti.name = kvp.Value;
                tracks.Add(ti);
            }
            video.Updater.SetAudiotracks(tracks);

            video.Updater.SetActiveAudiotrack(player.AudioTrack);

            video.Updater.SetChapterCount(player.Chapters);
            video.Updater.SetCurrentChapter(player.CurrentChapter);

        }


        void player_LanguageChanged(object sender, LanguageEventArgs e)
        {

            if (video.Audiotracks.Count > 0 && (video.ActiveAudiotrack < 0 || video.ActiveAudiotrack >= video.Audiotracks.Count || video.Audiotracks[video.ActiveAudiotrack].id != e.AudioTrack))
            {
                video.Updater.SetActiveAudiotrack(e.AudioTrack);
            }
            if (video.Subtitles.Count > 0 && e.Subtitle != -1 && (video.ActiveSubtitle < 0 || video.ActiveSubtitle >= video.Subtitles.Count || video.Subtitles[video.ActiveSubtitle].id != e.Subtitle))
            {
                video.Updater.SetActiveSubtitle(e.Subtitle);
            }

        }
    }
}
